import { getType } from "@/utils/core"
import { injectStyle, removeStyle } from "@/utils/dom"
import { App, DirectiveBinding } from "vue"
const eventMap = {
    mouseover: "mouseout",
    mouseout: "mouseover",

    mouseleave: "mouseenter",
    mouseenter: "mouseleave",

    mousedown: "mouseup",
    mouseup: "mousedown",

    touchstart: "touchend",
    touchend: "touchstart",

    focus: "blur",
    blur: "focus",

    click: "click",
    dblclick: "dblclick",

    keydown: "keyup",
    keyup: "keydown",

    wheel: "wheel",
    scroll: "scroll"
}
const SIGN_1 = "::"  // 设置相反事件 = toggle event
const SIGN_0 = ":"  // 设置事件
const SIGN_PATTERN = (str: string, colonNum: number | string = 1) => eval(`/(^|[^:]):{${colonNum}}([^:]|$)/`).test(str);
const DIRECTIVE_EVENTS_KEY = "directiveEvents"
export default function (app: App) {
    app.directive("style", {
        mounted(el: HTMLElement, binding: DirectiveBinding) {
            if (!el[DIRECTIVE_EVENTS_KEY]) el[DIRECTIVE_EVENTS_KEY] = {};
            changeStyleHandler(el, binding)
        },
        beforeUpdate(el: HTMLElement, binding: DirectiveBinding) {
            changeStyleHandler(el, binding)
        },
        beforeUnmount(el: HTMLElement, binding: DirectiveBinding) {
            if (el[DIRECTIVE_EVENTS_KEY] && Object.keys(el[DIRECTIVE_EVENTS_KEY]).length) {
                for (let key in el[DIRECTIVE_EVENTS_KEY]) {
                    el.removeEventListener(key, el[DIRECTIVE_EVENTS_KEY][key])
                }
                delete el[DIRECTIVE_EVENTS_KEY];
            }
        }
    })
}
// 情况一：v-style={color: 'red';...}   
// 情况二：v-style:color="red"
// 情况三：v-style:mouseover:background-color="red"
// 情况四：v-style:mouseover::background-color="red"
// 情况五：v-style:mouseover={background-color: 'red'}
function changeStyleHandler(el: HTMLElement, binding: DirectiveBinding) {
    let { arg, value } = binding;
    const args: string[] = [];
    // 如果value为对象，说明age不可能存在冒号
    if (getType(value) === 'Object') {
        // 且arg存在，事件表中也存在
        if (arg && eventMap[arg]) {
            // toggle事件绑定
            el[DIRECTIVE_EVENTS_KEY][arg] = setElEvent(el, arg, () => injectStyle(el, value));
            el[DIRECTIVE_EVENTS_KEY][eventMap[arg]] = setElEvent(el, eventMap[arg], () => removeStyle(el, value));
        } else
            // arg不存在，直接设置style对象中的样式
            if (!arg) {
                Object.keys(value).forEach(key => args.push(key));
                args.forEach(key => {
                    const colon = SIGN_PATTERN(key) ? SIGN_0 : SIGN_PATTERN(key, 2) ? SIGN_1 : null;
                    if (colon) {
                        const [eventName, styleName] = key.split(colon)
                        setToggleEvent(el, eventName, styleName, value[key], colon)
                    } else {
                        el.style[key] = value[key];
                    }
                })
            }
    } else
        // 如果value为string，arg存在
        if (getType(value) === 'string' && arg) {
            // 且没有冒号
            if (!/:/g.test(arg)) {
                el.style[arg] = value;
            } else {
                const colon = SIGN_PATTERN(arg) ? SIGN_0 : SIGN_PATTERN(arg, 2) ? SIGN_1 : null;
                if (colon) {
                    const [eventName, styleName] = arg.split(colon)
                    setToggleEvent(el, eventName, styleName, value, colon)
                }
            }
        }
}
function setToggleEvent(el: HTMLElement, eventName: string, styleName: string, value: string, colon: string) {
    el[DIRECTIVE_EVENTS_KEY][eventName] = setElEvent(el, eventName, () => (el.style[styleName] = value));
    if (colon === SIGN_1) {
        el[DIRECTIVE_EVENTS_KEY][eventMap[eventName]] =
            setElEvent(el, eventMap[eventName], () => (el.style.removeProperty(styleName)));
    }
}
function setElEvent(el: HTMLElement, eventName: string, handler: () => {}): EventListener {
    el.addEventListener(eventName, handler)
    return handler;
}
